<?php

namespace Biz\Middleware;

use Log;
use Closure;
use Biz\Services\App\AppService;
use Biz\Constants\App\AppConstants;
use Biz\Services\App\AppSiteService;
use Biz\Constants\ContainerConstants;
use Biz\Constants\ApplicationConstants;
use Biz\Services\Passport\ClientService;
use Lumen\Core\Exceptions\SystemException;
use Lumen\Security\Token\AppTokenSecurity;
use Illuminate\Auth\AuthenticationException;
use Lumen\Core\Exceptions\BusinessException;

/**
 * AppAuthorize.
 *
 * @license [http://www.85do.com] [杭州永奥网络科技有限公司]
 * @copyright Copyright (c) 2018-2026 Hangzhou Yongao Technology Co., Ltd. All rights reserved.
 */
class AppAuthorize
{
    /**
     * @var AppService
     */
    protected $appService;

    /**
     * @var AppSiteService
     */
    protected $appSiteService;

    /**
     * @var ClientService
     */
    protected $clientService;

    /**
     * Create a new middleware instance.
     *
     * @param AppService     $appService
     * @param AppSiteService $appSiteService
     * @param ClientService  $clientService
     *
     * @return AppAuthorize
     */
    public function __construct(AppService $appService, AppSiteService $appSiteService, ClientService $clientService)
    {
        $this->appService     = $appService;
        $this->appSiteService = $appSiteService;
        $this->clientService  = $clientService;
    }

    /**
     * Handle an incoming request.
     *
     * @param \Illuminate\Http\Request $request
     * @param \Closure                 $next
     *
     * @throws SystemException
     * @throws BusinessException
     * @throws AuthenticationException
     *
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if (false === $request->hasHeader(ApplicationConstants::HEADER_X_APP_AUTHORIZE_TOKEN)) {
            throw new BusinessException('抱歉，请传入应用授权Token');
        }

        if (! $request->has('oauth_user_id')) {
            throw new BusinessException('抱歉，请先使用app-auth中间件');
        }

        $oauthClientId = $request->get('oauth_client_id');
        if (empty($oauthClientId)) {
            throw new AuthenticationException;
        }

        $oauthClient = $this->clientService->find($oauthClientId);
        if (! $oauthClient) {
            throw new AuthenticationException;
        }

        $authorizeToken = $request->header(ApplicationConstants::HEADER_X_APP_AUTHORIZE_TOKEN);

        try {
            $security = new AppTokenSecurity($oauthClient->secret);
            $appId    = $security->decrypt($authorizeToken);
            $app      = $this->appService->find($appId);
        } catch (\Exception $e) {
            Log::error('AppAuthorize:'.$e->getMessage());
            throw new AuthenticationException;
        }

        if ($app->client_id != $oauthClientId) {
            throw new SystemException;
        }

        app('app')->singleton(ContainerConstants::BIZ_APP, function () use ($app) {
            return $app;
        });

        app('app')->singleton(ContainerConstants::BIZ_APP_USER, function () use ($app) {
            return $app->user;
        });

        $requestAdd = [
            'app_id' => $app->id,
        ];

        switch ($app->type) {
            case AppConstants::TYPE_WEB_SITE:
                $appSite               = $this->appSiteService->getSiteByApp($app);
                app('app')->singleton(ContainerConstants::BIZ_APP_SITE, function () use ($appSite) {
                    return $appSite;
                });
                $requestAdd['site_id'] = $appSite->id;
                break;
        }

        $request->request->add($requestAdd);

        return $next($request);
    }
}
